#ifndef CT_BYTE_BUFFER_H_
#define CT_BYTE_BUFFER_H_
#include "ct_mutex.h"
#include <stdint.h>
#include <vector>

const uint32_t trunkSize           = 64 * 1024;
const uint32_t maxSndBufferSize    = 1024*1024;       //snd_queue_ max size: 1M
const uint32_t maxEncBufferSize    = 1024*1024;       //enc_queue_ max size: 1.5M
#define unzip_size(zip_size) ((zip_size) * 120 / 100 + 12)
const uint32_t PACKET_ZIP_BUFFER   =  unzip_size(trunkSize - 1) + sizeof(uint32_t) + 8;

template <typename _type>
class ByteBuffer
{
        public:
                ByteBuffer();

                inline void Lock()
                {
                        m_Lock.lock();
                }
                inline void UnLock()
                {
                        m_Lock.unlock();
                }

                inline void put(const uint8_t *buf,const uint32_t size)
                {
                        wr_reserve(size);
                        bcopy(buf,&_buffer[_currPtr],size);
                        _currPtr += size;
                }
                inline uint32_t checkSndQueueLost()
                {
                        if (_maxSize > maxSndBufferSize) {
                                if (_currPtr > _offPtr) {
                                        uint32_t tmp = _currPtr - _offPtr;
                                        if (maxSndBufferSize > tmp) {
                                                memmove(&_buffer[0],&_buffer[_offPtr],tmp);
                                                _offPtr = 0;
                                                _currPtr = tmp;

                                                _maxSize = maxSndBufferSize;
                                        }
                                        else { //lost pkg
                                                _offPtr = 0;
                                                _currPtr = 0;

                                                swap_buffer_to_default_size();

                                                return tmp;
                                        }
                                }
                                else {
                                        _offPtr = 0;
                                        _currPtr = 0;

                                        swap_buffer_to_default_size();
                                }
                        }
                        return 0;
                }
                //return: allow put data to enc_queue
                inline bool checkEncQueueLost()
                {
                        if (_maxSize > maxEncBufferSize) {
                                if (_currPtr > _offPtr) {
                                        uint32_t tmp = _currPtr - _offPtr;
                                        if (maxEncBufferSize > tmp) {
                                                memmove(&_buffer[0],&_buffer[_offPtr],tmp);
                                                _offPtr = 0;
                                                _currPtr = tmp;

                                                _maxSize = maxEncBufferSize;
                                        }
                                        else {
                                                return false;
                                        }
                                }
                                else {
                                        _offPtr = 0;
                                        _currPtr = 0;
                                        swap_buffer_to_default_size();
                                }
                        }
                        return true;
                }

                inline uint8_t *wr_buf()
                {
                        return &_buffer[_currPtr];
                }

                inline uint8_t *rd_buf()
                {
                        return &_buffer[_offPtr];
                }

                inline bool rd_ready()
                {
                        bool ret = _currPtr > _offPtr;
                        return ret;
                }

                inline uint32_t rd_size()
                {
                        uint32_t ret = _currPtr - _offPtr;
                        return ret;
                }

                inline void rd_flip(uint32_t size)
                {	
                        if( size == 0 ) return;
                        _offPtr += size;
                        if (_currPtr > _offPtr) {
                                uint32_t tmp = _currPtr - _offPtr;
                                if (_offPtr >= tmp) {
                                        memmove(&_buffer[0],&_buffer[_offPtr],tmp);
                                        _offPtr = 0;
                                        _currPtr = tmp;
                                }
                        }
                        else {
                                _offPtr = 0;
                                _currPtr = 0;
                        }
                }
                inline void rd_flip_swap(uint32_t size)
                {
                        if( size == 0 ) return;
                        _offPtr += size;
                        if (_currPtr > _offPtr) {
                                uint32_t tmp = _currPtr - _offPtr;
                                if (_offPtr >= tmp) {
                                        memmove(&_buffer[0],&_buffer[_offPtr],tmp);
                                        _offPtr = 0;
                                        _currPtr = tmp;
                                }
                        }
                        else {
                                _offPtr = 0;
                                _currPtr = 0;

                                swap_buffer_to_default_size();
                        }
                }

                inline uint32_t wr_size()
                {
                        uint32_t ret = _maxSize - _currPtr;
                        return ret;
                }

                inline void wr_flip(const uint32_t size)
                {
                        _currPtr += size;
                }

                inline void reset()
                {
                        _offPtr = 0;
                        _currPtr = 0;
                }

                inline uint32_t maxSize() const
                {
                        return _maxSize;
                }

                inline void wr_reserve(const uint32_t size);
                inline void swap_buffer_to_default_size();

        public:
                ctMutex m_Lock;

        private:
                uint32_t _maxSize;
                uint32_t _offPtr;
                uint32_t _currPtr;
                _type _buffer;
};

typedef ByteBuffer<std::vector<uint8_t> > t_BufferCmdQueue;

        template <>
inline void t_BufferCmdQueue::wr_reserve(const uint32_t size)
{
        if (wr_size() < size) {
#define trunkCount(size) (((size) + trunkSize - 1) / trunkSize)
                _maxSize += (trunkSize * trunkCount(size));
                _buffer.resize(_maxSize);
        }
}

        template <>
inline void t_BufferCmdQueue::swap_buffer_to_default_size()
{
        if (_maxSize >= maxSndBufferSize) {
                std::vector<uint8_t>().swap(_buffer);
                _buffer.resize(trunkSize);
                _maxSize = trunkSize;
        }
}

typedef ByteBuffer<uint8_t [PACKET_ZIP_BUFFER]> t_StackCmdQueue;

        template <>
inline void t_StackCmdQueue::wr_reserve(const uint32_t size)
{
}

#endif //CT_BYTE_BUFFER_H_
